//! Windows COM port handler layer
//! 
//! This is based on the [pyserial project](https://github.com/pyserial/pyserial/blob/master/serial/serialwin32.py) 
//! by Chris Liechti <cliechti@gmx.net>



pub (crate) mod error;
pub mod port_lister;

use std::io::ErrorKind;

#[allow(unused)]
const XON: i8 = 17;
#[allow(unused)]
const XOFF: i8 = 19;
#[allow(unused)]
const CR: i8 = 13;
#[allow(unused)]
const LF: i8 = 10;



/// Serial port result type
pub type SerialResult<T> = std::result::Result<T, SerialError>;

/// Serial port error type
pub enum SerialError {
    /// IO Error
    IoError(std::io::Error),
    /// OS Specific error
    OsError {
        /// OS Error code
        code: u32,
        /// OS Error description
        desc: String,
    },
    /// Internal library error
    LibraryError(String)
}

/// Information on a listed serial port
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Default)]
pub struct PortInfo {
    /// Name of the device
    port: String,
    /// Hardware-ID of the device
    hwid: String,
    /// Vendor ID
    vid: u16,
    /// Product ID
    pid: u16,
    /// Manufacturer
    manufacturer: String,
    /// Description of the device
    description: String,
}

impl PortInfo {
    /// Gets port name
    pub fn get_port(&self) -> &str { &self.port }
    /// Gets port system hardware-ID
    pub fn get_hwid(&self) -> &str { &self.hwid }
    /// Gets port devices' ProductID
    pub fn get_pid(&self) -> u16 { self.pid }
    /// Gets port devices' VendorID
    pub fn get_vid(&self) -> u16 { self.vid }
    /// Gets port devices' manufacturer
    pub fn get_manufacturer(&self) -> &str { &self.manufacturer }
    /// Gets port devices' description
    pub fn get_desc(&self) -> &str { &self.description }
}


/// Scanner to list avaliable serial ports on a system
pub trait PortScanner {
    /// Lists avaliable serial ports on a system
    fn list_devices(&mut self) -> SerialResult<Vec<PortInfo>>;
}

impl From<SerialError> for std::io::Error {
    fn from(e: SerialError) -> Self {
        match e {
            SerialError::IoError(i) => i,
            SerialError::OsError { code: _ , desc } => std::io::Error::new(ErrorKind::Other, desc),
            SerialError::LibraryError(e) => std::io::Error::new(ErrorKind::Other, e),
        }
    }
}